package com.aiwiown.snackmq.broker.config;

import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
 * Broker 配置类，用于配置 Broker 的各种参数
 */
@Data
public class BrokerConfig {
    /**
     * Broker 主机名
     */
    private String host = "localhost";
    /**
     * Broker 端口（业务端口）
     */
    private int serverPort = 9876;

    /**
     * 数据存储路径
     */
    private String storePath = "data/store";

    //==========================Raft 相关配置============================
    /**
     * Raft 端口
     */
    private int raftPort = 9877;
    /**
     * Raft 集群 ID
     */
    private String raftGroupId = "snackmq-cluster";
    /**
     * Raft 数据存储路径
     */
    private String raftDataPath = "data/raft";
    /**
     * Raft 初始配置
     */
    private String raftInitialConf;
    /**
     * 快照间隔时间（秒）
     */
    private int snapshotIntervalSecs = 3600;

    /**
     * Raft 选举超时时间（毫秒）。 // 默认值为 1 秒
     * Follower 在此时间内未收到 Leader 心跳，将发起新一轮选举。
     * 对于资源受限的本地测试，建议调高此值以增加稳定性。
     */
    private int raftElectionTimeoutMs = 1000;
    /**
     * 是否启用自动伸缩
     */
    private boolean autoScalingEnabled = false;
    /**
     * 高吞吐量阈值
     */
    private double scalingHighTps = 10000.0;
    /**
     * 低吞吐量阈值
     */
    private double scalingLowTps = 2000.0;

    /**
     * 每个数据段的大小（默认 128MB）
     */
    private long segmentSize = 1024 * 1024 * 128;
    /**
     * 索引间隔（默认 4KB）
     */
    private int indexInterval = 4096;

    /**
     * Raft 地址
     */
    private String raftAddress;

    /**
     * 是否启用零拷贝读取模式
     * 启用后，ConsumeMessageHandler 将使用零拷贝存储服务进行高性能读取
     */
    private boolean zeroCopyEnabled = false;
    
    /**
     * 零拷贝读取的最大消息数量
     * 每次零拷贝读取时最多返回的消息数量
     */
    private int zeroCopyMaxMessages = 32;
    
    /**
     * 零拷贝读取的缓冲区大小（字节）  64KB
     * 用于优化零拷贝读取的性能
     */
    private int zeroCopyBufferSize = 64 * 1024;

    /**
     * Boss 线程数量
     */
    private int bossThreads = 1;
    
    /**
     * Worker 线程数量
     */
    private int workerThreads = Runtime.getRuntime().availableProcessors() * 2;

    /**
     * 最大连接数
     */
    private int maxConnections = 1000;
    
    /**
     * 最大分区数
     */
    private int maxPartitions = 100;
    
    /**
     * CPU 使用率阈值
     */
    private double cpuThreshold = 80.0;
    
    /**
     * 内存使用率阈值
     */
    private double memoryThreshold = 80.0;

    /**
     * 【新增】是否强制在启动时对所有日志段执行全量扫描恢复。
     * 默认值为 true (安全优先)。
     * 设置为 false 会启用基于索引的快速恢复，启动速度更快，但在极少数崩溃场景下可能存在风险。
     */
    private boolean forceFullLogRecovery = true;

    /**
     * 【修改】延迟消息的 TimerLog 每个段文件的大小（字节）。
     * 默认 16MB。当一个段文件写满后，会自动创建下一个。
     * 生产环境可以根据实际的延迟消息数量和保留策略进行调整。
     */
    private long timerLogSegmentSize = 16 * 1024 * 1024;

    /**
     * 事务消息超时时间（毫秒）。
     * 半消息超过此时间未被二次确认，将被回查。
     * 默认 60 秒。
     */
    private long transactionTimeoutMs = 60 * 1000;

    /**
     * 事务状态回查任务的执行间隔（毫秒）。
     * 默认 10 秒。
     */
    private long transactionCheckIntervalMs = 10 * 1000;

    /**
     * Raft 地址到 Business 端口映射
     */
    private Map<String, Integer> raftAddressToBusinessPortMap = new HashMap<>();


    /**
     * 【新增】是否启用认证和授权功能
     */
    private boolean authEnabled = false;

    /**
     * 【新增】JWT 签名的密钥，生产环境必须修改为一个长且随机的字符串
     */
    private String jwtSecretKey = "DefaultSecretKeyForSnackMQPleaseChangeMeInProduction";

    /**
     * 【新增】JWT 的过期时间（毫秒），默认为 24 小时
     */
    private long jwtExpirationMs = 24 * 60 * 60 * 1000;

    /**
     * 【新增】默认管理员用户名。
     * 仅在 authEnabled=true 且数据库中不存在此用户时，Broker 首次启动时会自动创建。
     */
    private String defaultAdminUser = "admin";

    /**
     * 【新增】默认管理员密码。
     * 仅在 authEnabled=true 且数据库中不存在此用户时，Broker 首次启动时会自动创建。
     */
    private String defaultAdminPassword = "admin";
    /**
     * 默认构造函数，使用向后兼容的端口配置
     */
    public BrokerConfig() {
        // 默认情况下，业务端口与 Raft 端口保持约定关系
        this.serverPort = this.raftPort - 1;
    }

    /**
     * 构造函数，支持显式指定业务端口
     *
     * @param host 主机名
     * @param raftPort Raft 端口
     * @param serverPort 业务端口
     */
    public BrokerConfig(String host, int raftPort, int serverPort) {
        this.host = host;
        this.raftPort = raftPort;
        this.serverPort = serverPort;
    }

    /**
     * 向后兼容的构造函数
     *
     * @param host 主机名
     * @param raftPort Raft 端口
     */
    public BrokerConfig(String host, int raftPort) {
        this(host, raftPort, raftPort - 1);
    }

    /**
     * 获取 Broker 地址
     *
     * @return Broker 地址，格式为 host:port
     */
    public String getBrokerAddress() {
        return this.host + ":" + this.serverPort;
    }

    /**
     * 获取 Raft 地址
     *
     * @return Raft 地址，格式为 host:raftPort
     */
    public String getRaftAddress() {
        return this.host + ":" + this.raftPort;
    }

}
